//------------------------------------------------------------------------------ 
//      Copyright (c) 2005-2009, Be Nanashi-San 
// 
//      Permission is hereby granted, free of charge, to any person obtaining a 
//      copy of this software and associated documentation files (the "Software"), 
//      to deal in the Software without restriction, including without limitation 
//      the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//      and/or sell copies of the Software, and to permit persons to whom the 
//      Software is furnished to do so, subject to the following conditions: 
// 
//      The above copyright notice and this permission notice shall be included in 
//      all copies or substantial portions of the Software. 
// 
//      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//      DEALINGS IN THE SOFTWARE. 
// 
//      File Name:	PrefWindow.cpp
//      Author: 	Be Nanashi-San 
//      Description:	 
//------------------------------------------------------------------------------
/*
	非互換PrefWindow.cpp
	NetPositiveライク設定Window
	生成で2chPositive/settingsからフラットなBMessageを読み込み、廃棄で保存する
	PrefWindowを利用する側は名前とタイプを知っていると仮定する。
	設定値はMessage()でBMessage*を受け取り、BMessageのFindxxx()関数を使って値を受け取る
	>> fPrefWindow->Message()->FindRect(kSETTING_WINDOW_RECT);
	PrefWindowで値が変更されて適用、またはOKでkUPDATEPREFSのBMessageをbe_appが受け取る。
	アプリケーションから値を設定するにはkUPDATEPREFSのBMessageにして送る。
		が面倒くさいかも。PrefWindowにReplacexxx()のような関数を作って直接更新する手もあるが
		Lock()、Unlock()が必要になる
*/

#include <TabView.h>
#include <Message.h>
#include <Button.h>
#include <RadioButton.h>
#include <TextControl.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Box.h>
#include <PopUpMenu.h>
#include <RadioButton.h>
#include <ScrollBar.h>
#include <StringView.h>
#include <Beep.h>
#include <stdio.h>
#include <stdlib.h>
#include <ClassInfo.h>

#include "config.h"
#include "2chPositive.h"
#include "PrefWindow.h"
#include "messages.h"
#include "TSettings.h"
#include "setting.h"
#include "Util.h"

static const uint32 kOKBUTTON = 'kOKB';
static const uint32 kCANSELBUTTON = 'kCNB';
static const uint32 kAPPLYBUTTON = 'kAPB';
static const uint32 kCONTROL_CHANGED  = 'kDPY';
////////////////////////////////////////////////////////////////////////////////
// IEtoBRect
//
//
////////////////////////////////////////////////////////////////////////////////
inline BRect
IEtoBRect(float x, float y, float w, float h)
{
	return  BRect(x, y, x + w - 1 , y + h - 1 );
}
////////////////////////////////////////////////////////////////////////////////
// CreateMenuFontsList
//
//
////////////////////////////////////////////////////////////////////////////////
static BPopUpMenu*
CreateMenuFontsList(const char *name)
{
	//　20060728:name追加。（BeOS - Zeta R5すれ@360：Be名無しさん より）
	BPopUpMenu *menu = new BPopUpMenu(name);
	int32 numFamilies = count_font_families();
	for (int32 i = 0; i < numFamilies; i++) {
		font_family family;
		uint32 flags;
		if (get_font_family(i, &family, &flags) == B_OK) {
			BMessage *m = new BMessage(kCONTROL_CHANGED);
			m->AddString("name", name);
			menu->AddItem(new BMenuItem(family, m));
		}
	}

	return menu;
}
////////////////////////////////////////////////////////////////////////////////
// CreateMenuStringList
//
//
////////////////////////////////////////////////////////////////////////////////
static BPopUpMenu*
CreateMenuStringList(const char *name)
{
	const char *fontsize[] = { "9", "10", "11", "12", "13", "14", "16", "18", "20", "24", NULL };
	const char **argv = fontsize;
	//　20060728:name追加。（BeOS - Zeta R5すれ@360：Be名無しさん より）
	BPopUpMenu *menu = new BPopUpMenu(name);
	while (*argv) {
		BMessage *m = new BMessage(kCONTROL_CHANGED);
		m->AddString("name", name);
		menu->AddItem(new BMenuItem(*argv, m));
		argv++;
	}
	return menu;
}
////////////////////////////////////////////////////////////////////////////////
// 
//
//
////////////////////////////////////////////////////////////////////////////////
PrefView::PrefView(BRect frame, const char *name)
	: BView(frame, name, B_FOLLOW_ALL, B_WILL_DRAW)
{
}
////////////////////////////////////////////////////////////////////////////////
// CreateMenuField
//
// 20060717:BeOS - Zeta R5スレの312@Be名無しさんより、
// 長いフォント名でも省略されずに表示するよう修正。
////////////////////////////////////////////////////////////////////////////////
/* BMenuFieldはそのViewとmenuを表示するための_mc_mb_Viewから構成される。
	Viewの大きさはframeで固定ではなくmenu表示に必要な大きさで増減する。
	最大値としては意味がある */
void
PrefView::CreateMenuField(BRect frame, const char *label, BMenu *menu)
{
	BMenuField* aMenuField = new BMenuField(frame, "mField", label, menu);
	float width = be_plain_font->StringWidth(label);
	if (width > 50) {
		aMenuField->SetDivider(110.0);
		aMenuField->SetAlignment(B_ALIGN_RIGHT);
	} else {
		aMenuField->SetDivider(50.0);
		aMenuField->SetAlignment(B_ALIGN_LEFT);
	}
	this->AddChild(aMenuField);
}
////////////////////////////////////////////////////////////////////////////////
// MakeRadioButton
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::MakeRadioButton(BRect r,  const char *name, const char *label, uint32 command)
{
	::MakeRadioButton(r, name, label, command, this);
}
////////////////////////////////////////////////////////////////////////////////
// MakeChackBox
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::MakeCheckBox(BRect r,  const char *name, const char *label, uint32 command)
{
	::MakeCheckBox(r, name, label, command, this);
}
////////////////////////////////////////////////////////////////////////////////
// MakeButton
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::MakeButton(BRect r, const char *label, uint32 command, bool b)
{
	::MakeButton(r, label, command, this, b);
}
////////////////////////////////////////////////////////////////////////////////
// MakeTextField
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::MakeTextField(BRect r,  const char *name, const char *label, uint32 command, float divide)
{
	BTextControl* aTextControl1 = new BTextControl(r, name, label, "", new BMessage(command));
	aTextControl1->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
	aTextControl1->SetDivider(divide);
	this->AddChild(aTextControl1);
}
////////////////////////////////////////////////////////////////////////////////
// SetRadioButton
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::SetRadioButton(int32 id, const char *value)
{
	PrefWindow *w = (PrefWindow *)Window();
	const char *s = w->FindMessage(value);
	BRadioButton *target = (BRadioButton*)ChildAt(id);

	if (target && s && *s) { 
		int32 i = atoi(s);
		target->SetValue(i);
	}
}
////////////////////////////////////////////////////////////////////////////////
// SetRadioButton
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::SetCheckBox(int32 id, const char *value)
{
	PrefWindow *w = (PrefWindow *)Window();
	const char *s = w->FindMessage(value);
	BRadioButton *target = (BRadioButton*)ChildAt(id);

	if (target && s && *s) { 
		int32 i = atoi(s);
		target->SetValue(i);
	}
}
////////////////////////////////////////////////////////////////////////////////
// SetTextField
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::SetTextField(int32 id, const char *value)
{
	PrefWindow *w = (PrefWindow *)Window();
	const char *s = w->FindMessage(value);
	BTextControl *target = (BTextControl*)ChildAt(id);

	if (target && s && *s) { 
		target->SetText(s);
	}
}
////////////////////////////////////////////////////////////////////////////////
// SetMarkeMenuField
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefView::SetMarkeMenuField(int32 id, const char *value)
{
	PrefWindow *w = (PrefWindow *)Window();
	const char *s = w->FindMessage(value);
	BMenuField *target = (BMenuField*)ChildAt(id);

	if (target && s && *s) { 
		BMenuItem* menuItem = target->Menu()->FindItem(s);
		if (menuItem) menuItem->SetMarked(true);
	}
}

////////////////////////////////////////////////////////////////////////////////
// 
//
//
////////////////////////////////////////////////////////////////////////////////
DisplayPrefs::DisplayPrefs(BRect frame)
	: PrefView(frame, "表示")
{
	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	
	CreateMenuField(IEtoBRect(10, 10, 280, 25), "板一覧フォント:", CreateMenuFontsList(DISPLAY_BOARD_FONT_NAME));
	CreateMenuField(IEtoBRect(290, 10, 110, 25), "サイズ:", CreateMenuStringList(DISPLAY_BOARD_FONT_SIZE));
	CreateMenuField(IEtoBRect(10, 35, 280, 25), "スレ一覧フォント:", CreateMenuFontsList( DISPLAY_RESLIST_FONT_NAME));
	CreateMenuField(IEtoBRect(290, 35, 110, 25),"サイズ:", CreateMenuStringList(DISPLAY_RESLIST_FONT_SIZE));
	CreateMenuField(IEtoBRect(10, 60, 280, 25), "スレフォント:", CreateMenuFontsList(DISPLAY_RES_FONT_NAME));
	CreateMenuField(IEtoBRect(290, 60, 110, 25), "サイズ:", CreateMenuStringList(DISPLAY_RES_FONT_SIZE));

	AddChild(new BBox(IEtoBRect(10, 90, 380, 2))); 

	AddChild(new BStringView(IEtoBRect(10, 100, 300, 20),"","スレを開いたときの表示方法"));
	
	MakeRadioButton(IEtoBRect(20, 120, 300, 20), DISPLAY_ALL_THREAD, "全てのレスを表示", kCONTROL_CHANGED);
	MakeRadioButton(IEtoBRect(20, 140, 300, 20), DISPLAY_FIRST_THREAD, "1から表示量分のレスを表示", kCONTROL_CHANGED);
	MakeRadioButton(IEtoBRect(20, 160, 300, 20), DISPLAY_LAST_THREAD, "最後から表示量分のレスを表示", kCONTROL_CHANGED);

	MakeTextField(IEtoBRect(10, 190, 130, 20), DISPLAY_THREAD_RANGE, "レス表示量：", kCONTROL_CHANGED, 90.0);
}
////////////////////////////////////////////////////////////////////////////////
// AllAttached
//
//　20060728:AttachedWindow()から変更。（BeOS - Zeta R5すれ@360：Be名無しさん より）
////////////////////////////////////////////////////////////////////////////////
void
DisplayPrefs::AllAttached()
{
	const char *s[]={DISPLAY_BOARD_FONT_NAME,DISPLAY_BOARD_FONT_SIZE,
				DISPLAY_RESLIST_FONT_NAME,DISPLAY_RESLIST_FONT_SIZE,
				DISPLAY_RES_FONT_NAME,DISPLAY_RES_FONT_SIZE};
	

	for(int32 i = 0; i < 6; i++){			
		SetMarkeMenuField(i, (s[i]));
	}

	SetRadioButton(8, DISPLAY_ALL_THREAD);
	SetRadioButton(9, DISPLAY_FIRST_THREAD);
	SetRadioButton(10, DISPLAY_LAST_THREAD);

	SetTextField(11, DISPLAY_THREAD_RANGE);
}
////////////////////////////////////////////////////////////////////////////////
// 
//
//
////////////////////////////////////////////////////////////////////////////////
ConnectionPrefs::ConnectionPrefs(BRect frame)
	: PrefView(frame, "接続")
{
	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	BMenu *aMenu = new BPopUpMenu(GENERAL_CHANNEL);
	aMenu->AddItem(new BMenuItem("2ch", new BMessage(kCONTROL_CHANGED)));
	aMenu->AddSeparatorItem();
	aMenu->AddItem(new BMenuItem("Add BBS"B_UTF8_ELLIPSIS, new BMessage(kCONTROL_CHANGED)));

	BMenuField* aMenuField = new BMenuField(IEtoBRect(30, 10, 250, 25), "BBS", "BBS:", aMenu);
	aMenuField->SetAlignment(B_ALIGN_RIGHT);
	aMenuField->SetDivider(90.0);
	AddChild(aMenuField);

	MakeTextField(IEtoBRect(30, 50, 260, 20), GENERAL_LINKPROXY, "外部リンク用：", kCONTROL_CHANGED, 90.0);
	MakeTextField(IEtoBRect(30, 80, 260, 20), GENERAL_BBSURL, "板一覧のURL：", kCONTROL_CHANGED, 90.0);
	MakeTextField(IEtoBRect(30, 110, 260, 20), GENERAL_PROXY, "プロキシ：", kCONTROL_CHANGED, 90.0);
	MakeTextField(IEtoBRect(30, 140, 130, 20), GENERAL_PORT, "ポート：", kCONTROL_CHANGED, 90.0);


}
////////////////////////////////////////////////////////////////////////////////
// AllAttached
//
//　20060728:AttachedWindow()から変更。（BeOS - Zeta R5すれ@360：Be名無しさん より）
////////////////////////////////////////////////////////////////////////////////
void
ConnectionPrefs::AllAttached()
{
	SetMarkeMenuField(0, GENERAL_CHANNEL);

	const char *name[] = { GENERAL_LINKPROXY, GENERAL_BBSURL, GENERAL_PROXY, GENERAL_PORT };
	for (int32 i = 1; i < 5; i++)
		SetTextField(i, name[i-1]);
}
////////////////////////////////////////////////////////////////////////////////
// 
//
//
////////////////////////////////////////////////////////////////////////////////
CachePrefs::CachePrefs(BRect frame)
	: PrefView(frame, "その他")
{
	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	MakeTextField(IEtoBRect(30, 10, 360, 20), GENERAL_CHACHE_PATH, "キャッシュのパス：", kCONTROL_CHANGED, 120.0);
	MakeButton(IEtoBRect(150, 37, 160, 28), "キャッシュを削除", kMSG_CLEAR_ALL_CACHE);
	MakeTextField(IEtoBRect(30, 70, 160, 20), GENERAL_HISTORY_COUNT, "履歴保持数：", kCONTROL_CHANGED, 120.0);
	MakeCheckBox(IEtoBRect(150, 100, 200, 20), GENERAL_BBS_LOAD, "起動時に板一覧を読込む", kCONTROL_CHANGED);
}
////////////////////////////////////////////////////////////////////////////////
// AllAttached
//
//　20060728:AttachedWindow()から変更。（BeOS - Zeta R5すれ@360：Be名無しさん より）
////////////////////////////////////////////////////////////////////////////////
void
CachePrefs::AllAttached()
{
	SetTextField(0, GENERAL_CHACHE_PATH);
	SetTextField(2, GENERAL_HISTORY_COUNT);
}
////////////////////////////////////////////////////////////////////////////////
// コンストラクタ
//
//
////////////////////////////////////////////////////////////////////////////////
PrefWindow::PrefWindow()
	:	Dialog(IEtoBRect(300,200,400,300), "2ch+設定")
	, fChanged(false)
{
	this->CloneMessage();
	BView * contentView = new BView(this->Bounds(), "ContentView", B_FOLLOW_ALL, B_WILL_DRAW);
	contentView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	this->AddChild(contentView);
	
	BRect frame(Bounds());
	float left = frame.right - 9 - 106 - 106 - 80;
	float top = frame.bottom - 27 - 9;
	MakeButton(IEtoBRect(left,top, 80, 27), "キャンセル", kCANSELBUTTON, contentView);
	MakeButton(IEtoBRect(left + 106, top, 80, 27), "適用", kAPPLYBUTTON, contentView, false);
	BButton *aButton3 = MakeButton(IEtoBRect(left + 106 + 106, top, 80, 27), "OK", kOKBUTTON, contentView, false);
	this->SetDefaultButton(aButton3); /* BTextControlでEnterされるとDefaultButtonが受け取ってしまいBTextControlから
																BMessageが飛んで来ない */
	frame.top = 10;
	frame.bottom -= 44;
	fTabView = new BTabView(frame, "TabContain", B_WIDTH_FROM_LABEL);
	frame.top = 0;
	frame.bottom -= 13 + fTabView->TabHeight();
	fTabView->AddTab(new ConnectionPrefs(frame));
	fTabView->AddTab(new DisplayPrefs(frame));
	fTabView->AddTab(new CachePrefs(frame));
	contentView->AddChild(fTabView);
}
////////////////////////////////////////////////////////////////////////////////
// ~PrefWindow
//
//
////////////////////////////////////////////////////////////////////////////////
PrefWindow::~PrefWindow()
{
}
////////////////////////////////////////////////////////////////////////////////
// MessageReceived
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::MessageReceived(BMessage *msg)
{
	// BeOS - Zeta R5スレ@360氏より。
	// 設定ウインドウで何か変更してOKした後、再度設定ウインドウで
	// 何か変更すると落ちる原因はfCloneがNULLになっているせいでした。
	if (fClone.IsEmpty()) this->CloneMessage();
	
	switch (msg->what) {
	case kCONTROL_CHANGED:
		this->ModifiedMessage(msg);
		break;
	case kOKBUTTON:
	case kAPPLYBUTTON:
	case kCANSELBUTTON:
		this->DispatchButton(msg);
		break;
	case kUPDATEPREFS: 
	/* 設定のfMessageをmsgで更新する。直接更新するという手もあるが */
		this->UpdateMessage(msg);
		break;
	case kMSG_CLEAR_ALL_CACHE:
		ClearBBSCache();
		break;
	default:
		BWindow::MessageReceived(msg);
		break;
	}
}
////////////////////////////////////////////////////////////////////////////////
// QuitRequested
//
//
////////////////////////////////////////////////////////////////////////////////
bool
PrefWindow::QuitRequested()
{
	bool internal = CurrentMessage();
	if (internal)
		this->Hide();
	else
		this->DeleteCloneMessage();
	
	return ! internal;
}
////////////////////////////////////////////////////////////////////////////////
// DispatchButton
//
/* msgからButtonを判定してSave、Quitを行う */
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::DispatchButton(BMessage *msg)
{
	uint32 what = msg->what;
	
	if(what == kOKBUTTON || what == kAPPLYBUTTON){
		BMessage *diff = this->DiffMessage(theSettings().Settings());
		if (!diff->IsEmpty()){
			//20060923
			be_app_messenger.SendMessage(diff);
		}
		delete diff;
		theSettings().SetTo(fClone);
	}
	
	if(what == kOKBUTTON || what == kCANSELBUTTON){
		DeleteCloneMessage();
		this->PostMessage(B_QUIT_REQUESTED);
	}
	ButtonEnable(false); /* いずれにしろ更新はクリアーされるので */
}
////////////////////////////////////////////////////////////////////////////////
// ModifiedMessage
//
/* msgから更新されたnameとvalueを入手してfCloneへ反映させる */
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::ModifiedMessage(BMessage *msg)
{
	BArchivable *object;
	if (msg->FindPointer("source", (void**)&object) == B_OK) {
		const char *name = NULL, *value = NULL;
		if (is_instance_of(object, BMenuItem)) {
			BMenuItem* target = static_cast<BMenuItem*>(object);
			name = msg->FindString("name"); //20060720
			value = target->Label();
		}else if (is_instance_of(object, BTextControl)) {
			BTextControl* target = static_cast<BTextControl*>(object);
			name = target->Name();
			value = target->Text();
		}else if (is_instance_of(object, BRadioButton)) {
			BRadioButton* target = static_cast<BRadioButton*>(object);
			BView* owner = target->Parent();
			BView* child = NULL;
			// BeOS - Zeta R5スレ@384：Be名無しさん より。
			// ラジオボタンオフに対応。
			for (int32 i = 0; (child = owner->ChildAt(i)); i++) {
				BRadioButton *radio = cast_as(child, BRadioButton);
				if (radio && radio != target ) {
					name = radio->Name();
					if (strcmp(fClone.FindString(name), "1") == 0) {
						fClone.RemoveName(name);
						fClone.AddString(name, "0");
						break; // あってもなくてもいい
					}
				}
			}
			name = target->Name();
			value = "1";// Radioはonしか報告しない。
		}else{
			return;
		}
			
		//printf("target=%s, value=%s\n", name, value);
		
		/* fCloneを更新する */
		if (fClone.HasString(name))
			fClone.RemoveName(name);

		fClone.AddString(name, value);

		fChanged = true;
		ButtonEnable(true);
	}
}
////////////////////////////////////////////////////////////////////////////////
// CloneMessage
//
/* fMessageのコピー(fMessageを直接変更してはならない)を作成する*/
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::CloneMessage()
{
	theSettings().MakeCopy(fClone);
}
////////////////////////////////////////////////////////////////////////////////
// DeleteCloneMessage
//
/* fMessageのコピーを削除する*/
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::DeleteCloneMessage()
{
		fClone.MakeEmpty();
		fChanged = false;
}
////////////////////////////////////////////////////////////////////////////////
// UpdateMessage
//
/* msgでfMessageを更新する。indexは考慮されない。*/
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::UpdateMessage(BMessage *msg)
{
	BMessage *fMessage = theSettings().Settings();
	CONST_DANO char *nameFound;
	type_code typeFound;
	int32 countFound, i = 0;
	while (msg->GetInfo(B_ANY_TYPE, i++, &nameFound, &typeFound, &countFound) == B_OK) {
		const void *data = NULL;
		ssize_t numBytes = 0;
		msg->FindData(nameFound, typeFound, 0, &data, &numBytes);
		if (fMessage->HasData(nameFound, typeFound))
			fMessage->RemoveName(nameFound);

	/* 何故かB_STRING_TYPEのものをAddData()するとPrintToStream()で変に表示される。
		FindString()では問題なく受け取れるのだが？ ReplaceDataは問題ないのか？ */
		if (typeFound == B_STRING_TYPE)
			fMessage->AddString(nameFound, (const char*)data);
		else
			fMessage->AddData(nameFound, typeFound, data, numBytes);
		
		fChanged = true;
	}
	
	if (fChanged) ButtonEnable(true);
	/* 既にfCloneされていたら削除して再設定する必要がある */
	if (!fClone.IsEmpty()) {
		this->CloneMessage();
		BView *active = fTabView->ViewForTab(fTabView->Selection());
		active->AllAttached();	/* 呼び出してもいいのか */
	}
}
////////////////////////////////////////////////////////////////////////////////
// DiffMessage
//
/* fCloneにある物でdstと異なるものを抽出する */
////////////////////////////////////////////////////////////////////////////////
BMessage*
PrefWindow::DiffMessage(BMessage *dst)
{
	BMessage *diff = new BMessage(kUPDATEPREFS);
	CONST_DANO char *nameFound;
	type_code typeFound;
	int32 countFound, t = 0;
	while (fClone.GetInfo(B_ANY_TYPE, t++, &nameFound, &typeFound, &countFound) == B_OK) {
		for (int32 i = 0; i < countFound; i++) {
			const void *data = NULL;
			ssize_t numBytes = 0;
			fClone.FindData(nameFound, typeFound, i, &data, &numBytes);
			if (dst->HasData(nameFound, typeFound, i)) {
				const void *data2 = NULL;
				ssize_t numBytes2 = 0;
				dst->FindData(nameFound, typeFound, i, &data2, &numBytes2);
				if (numBytes == numBytes2 && memcmp(data, data2, numBytes) == 0)
					continue;
			}
		/* 何故かB_STRING_TYPEのものをAddData()するとPrintToStream()で変に表示される。
			FindString()では問題なく受け取れるのだが？ */
			if (typeFound == B_STRING_TYPE)
				diff->AddString(nameFound, (const char*)data);
			else
				diff->AddData(nameFound, typeFound, data, numBytes);
		}
	}
	return diff;
}
////////////////////////////////////////////////////////////////////////////////
// ButtonEnable
//
//
////////////////////////////////////////////////////////////////////////////////
void
PrefWindow::ButtonEnable(bool flags)
{
	((BButton*)(ChildAt(0)->ChildAt(1)))->SetEnabled(flags);
	((BButton*)(ChildAt(0)->ChildAt(2)))->SetEnabled(flags);
}
